/**
 * @file engineer_mode_hardware_testing.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_watch.h"

#if USE_LV_WATCH_ENGINEER_MODE!= 0
#include <stdlib.h>
/*********************
 *      DEFINES
 *********************/
#define ENGINEER_MODE_HARDWARE_TESTING_LIST_CNT    13
#define TOUCH_SCR_TEST_LCD_AREA_CNT       28
#define DISPLAY_TEST_LCD_COLOR_TIME_OUT   3000
#define MIC_RECORD_AMR_HEAD_SIZE 6
#define MIC_RECORD_MAX_RECORD_DURATION 3 /*in seconds*/
#define MIC_RECORD_MAX_RECORD_SIZE MIC_RECORD_MAX_RECORD_DURATION * HAL_AMR_BUFSIZE_PER_SECOND + MIC_RECORD_AMR_HEAD_SIZE
#define LTE_BANDH_LIST_CNT   4
#define LTE_BANDL_LIST_CNT   9
/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void emht_presskey_create(lv_obj_t * par);
static void emht_touch_screen_create(lv_obj_t * par);
static void emht_tp_pointer_create(lv_obj_t * par);
static void emht_display_create(lv_obj_t * par);
static void emht_camera_create(lv_obj_t * par);
static void emht_speaker_create(lv_obj_t * par);
static void emht_micphone_create(lv_obj_t * par);
static void emht_memory_create(lv_obj_t * par);
static void emht_backlight_create(lv_obj_t * par);
static void emht_gravity_create(lv_obj_t * par);
static void emht_battery_create(lv_obj_t * par);
static void emht_vibration_create(lv_obj_t * par);
static void hwtest_camera_pre_select_btn_rel_action(lv_obj_t * btn, lv_event_t e);
static void hardware_testing_btn_rel_event_cb(lv_obj_t * btn, lv_event_t e);
static void hardware_testing_prepare_destory(lv_obj_t * activity_obj);
static lv_obj_t * hardware_testing_startbtn_create(lv_obj_t * par, lv_event_cb_t event_cb);
static void hardware_testing_result_timer_func(void * param);
static void hardware_testing_result_create(lv_obj_t * par, engineer_mode_test_res_t res);
static void hardware_testing_fail_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void hardware_testing_success_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void hardware_testing_resultbtn_create(lv_obj_t * par, uint8_t num);
static bool hardware_testing_match_obj(void);
static void hardware_testing_item_prepare_destory(lv_obj_t * activity_obj);
static void touch_screen_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static lv_res_t touch_screen_lcdarea_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param);
static void display_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void display_lcdcolor_timer_func(void * param);
static void display_test_result_create(lv_obj_t * par);
static lv_obj_t * camera_pre_select_btn(lv_obj_t * par);
static void camera_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void camera_preview_task(lv_task_t * task);
static void camera_destory(void);
static void speaker_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void speaker_stop_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void micphone_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void ht_micphone_record_play_over_cb(void * para);
static void ht_micphone_record_task_cb(lv_task_t * task);
static void ht_micphone_record_cb(MCI_EVNET_T event, MCI_INFO_T info_type, int32_t value);
static void backlight_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void backlight_change_anim(lv_anim_t * anim);
static void battery_charging_status_update(lv_anim_t * anim);
static void vibration_start_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void vibration_stop_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void emht_tp_pointer_prepare_destroy(lv_obj_t * par);
static void emht_camera_prepare_destory(lv_obj_t * activity_obj);
static void emht_speaker_prepare_destory(lv_obj_t * activity_obj);
static void emht_micphone_prepare_destory(lv_obj_t * activity_obj);
static void emht_backlight_prepare_destory(lv_obj_t * activity_obj);
static void emht_vibration_prepare_destory(lv_obj_t * activity_obj);
static void emht_alarm_prepare_destory(lv_obj_t * activity_obj);
static void emht_alarm_create(lv_obj_t * par);
static void alarm_get_yearopt_from_year(uint16_t year, char * yearopt);
static void alarm_get_optstr_from_num(uint8_t num, uint8_t num2, char * stropt, uint8_t type, uint8_t leapyear);
static uint8_t alarm_get_daycnt_from_month(uint8_t month, uint8_t leapyear);
static uint8_t alarm_isleapyear(uint32_t year);
static void alarm_date_roller_event_cb(lv_obj_t * roller, lv_event_t e);
static void alarm_time_roller_event_cb(lv_obj_t * roller, lv_event_t e);
static lv_obj_t * alarm_date_time_roller_create(lv_obj_t * par, uint8_t type, hal_rtc_t * date_time);
static void alarm_setting_create(lv_obj_t * par, uint8_t type, lv_event_cb_t ok_event, lv_event_cb_t can_event);
static void alarm_get_num_from_string(char * str, char * delimiters, hal_rtc_t * date_time);
static void alarm_active_callback(void);
static void alarm_setting_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void alarm_setting_datetime_ok_btn_event_cb(lv_obj_t * btn, lv_event_t e);
static void alarm_setting_datetime_cancel_btn_event_cb(lv_obj_t * btn, lv_event_t e);

extern char * gcvt(double value, int32_t ndigit, char * buf);
/**********************
 *  STATIC VARIABLES
 **********************/
const lv_engineer_item_t engineer_mode_hardware_testing_list[ENGINEER_MODE_HARDWARE_TESTING_LIST_CNT] = {
    { WATCH_TEXT_ID_PRESS_KEY, emht_presskey_create, hardware_testing_item_prepare_destory },
    { WATCH_TEXT_ID_TOUCH_SCR, emht_touch_screen_create, hardware_testing_item_prepare_destory },
    { WATCH_TEXT_ID_TP_POINTER, emht_tp_pointer_create, emht_tp_pointer_prepare_destroy },
    { WATCH_TEXT_ID_DISPLAY_SCR, emht_display_create, hardware_testing_item_prepare_destory },
    { WATCH_TEXT_ID_TR_CAMERA, emht_camera_create, emht_camera_prepare_destory },
    { WATCH_TEXT_ID_SPEAKER, emht_speaker_create, emht_speaker_prepare_destory },
    { WATCH_TEXT_ID_MICPHONE, emht_micphone_create, emht_micphone_prepare_destory },
    { WATCH_TEXT_ID_MEMORY, emht_memory_create, hardware_testing_item_prepare_destory },
    { WATCH_TEXT_ID_BACKLIGHT, emht_backlight_create, emht_backlight_prepare_destory },
    { WATCH_TEXT_ID_GRAVITY, emht_gravity_create, hardware_testing_item_prepare_destory },
    { WATCH_TEXT_ID_BATTERY, emht_battery_create, hardware_testing_item_prepare_destory },
    { WATCH_TEXT_ID_VIBRATION, emht_vibration_create, emht_vibration_prepare_destory },
    { WATCH_TEXT_ID_EMODE_HW_ALARM,  emht_alarm_create, emht_alarm_prepare_destory },
};
static lv_signal_cb_t orignal_btn_signal;

/* AT*BAND <ltebandh>: integer type */
const uint16_t lte_bandh_list[LTE_BANDH_LIST_CNT][2] = {
    /* band, reg_val */
    { 38, 0x20 },
    { 39, 0x40 },
    { 40, 0x80 },
    { 41, 0x100 }
};

/* AT*BAND <ltebandl>: integer type */
const uint32_t lte_bandl_list[LTE_BANDL_LIST_CNT][2] = {
    /* band, reg_val */
    { 1,  0x1 },
    { 2,  0x2 },
    { 3,  0x4 },
    { 4,  0x8 },
    { 5,  0x10 },
    { 7,  0x40 },
    { 13, 0x1000 },
    { 17, 0x10000 },
    { 20, 0x80000 }
};

/**********************
 *      MACROS
 **********************/
#define ALARM_SETTING_TIME_MIN_YEAR         2017
#define ALARM_SETTING_TIME_MAX_YEAR         2037
#define ALARM_SETTING_TIME_YEAR_LOOP_CNT    (ALARM_SETTING_TIME_MAX_YEAR - ALARM_SETTING_TIME_MIN_YEAR + 1)
#define ALARM_SETTING_TIME_STR_LENGTH       12

/**********************
 *   GLOBAL FUNCTIONS
***********************/
lv_obj_t * engineer_mode_hardware_testing_create(lv_obj_t * activity_obj)
{
    lv_obj_t * obj;
    if(NULL == activity_obj) {
        lv_watch_activity_ext_t activity_ext;
        memset(&activity_ext, 0, sizeof(lv_watch_activity_ext_t));
        activity_ext.actId = ACT_ID_ENGINEER_MODE_HARDWARETESTING;
        activity_ext.create = engineer_mode_hardware_testing_create;
        activity_ext.prepare_destory = hardware_testing_prepare_destory;
        activity_obj = lv_watch_creat_activity_obj(&activity_ext);
        LV_ASSERT_MEM(activity_obj);
        if(NULL == activity_obj) {
            return NULL;
        }
    }

    obj = lv_watch_obj_create(activity_obj);
    LV_ASSERT_MEM(obj);
    if(NULL == obj) {
        return NULL;
    }
    printf("%s watch_obj %p\n", __FUNCTION__, activity_obj);

    /*Allocate the object type specific extended data*/
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = lv_obj_allocate_ext_attr(activity_obj, sizeof(lv_engineer_hardware_testing_obj_ext_t));
    LV_ASSERT_MEM(ht_ext);
    if(NULL == ht_ext) {
        return NULL;
    }
    memset((char *)ht_ext + sizeof(lv_watch_activity_ext_t), 0, sizeof(lv_engineer_hardware_testing_obj_ext_t) - sizeof(lv_watch_activity_ext_t));
    ht_ext->lcdarea_click_num = 0;
    ht_ext->camera_lte_btn = false;

    lv_obj_t * title = lv_label_create(obj, NULL);
    lv_obj_set_size(title, LV_HOR_RES, LV_VER_RES / 4);
    lv_label_set_text_id(title, WATCH_TEXT_ID_ENGINEER_MODE_HARDWARETESTING);
    lv_obj_add_style(title, LV_LABEL_PART_MAIN, &lv_watch_font30);
    lv_obj_align(title, NULL, LV_ALIGN_IN_TOP_MID, 0, 5);

    lv_obj_t * list = lv_list_create(obj, NULL);
    lv_obj_set_size(list, LV_HOR_RES, LV_VER_RES - lv_obj_get_height(title) - 20);
    lv_page_set_edge_flash(list, true);
    lv_obj_add_style(list, LV_LIST_PART_EDGE_FLASH, &lv_watch_cont_opa1);
    lv_obj_align(list, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

    lv_engineer_main_obj_ext_t * ext = engineer_mode_get_ext();
    lv_obj_add_style(list, LV_LIST_PART_BG,  &lv_watch_style_transp);

    uint8_t i = 0;
    lv_obj_t * btn;
    lv_obj_t * label;
    for(i = 0; i < ENGINEER_MODE_HARDWARE_TESTING_LIST_CNT; i++) {
        btn = lv_list_add_btn(list, NULL, lv_lang_get_text(engineer_mode_hardware_testing_list[i].txtId));
        lv_watch_set_free_num(btn, i);
        lv_watch_obj_add_element(btn);
        lv_obj_add_style(btn, LV_BTN_PART_MAIN, &(ext->list_btn_st));
        lv_obj_set_event_cb(btn, hardware_testing_btn_rel_event_cb);

        label = lv_obj_get_child(btn, NULL);
        lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
        lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
        lv_obj_set_width(label, LV_HOR_RES - 10);
    }

    lv_obj_set_click(list, true);

    return obj;
}

#if USE_CRANE_WATCH_KEYPAD
void hardware_testing_key_event(struct keypad_param * arg)
{
    static uint8_t last_event = KEY_EVENT_NONE;
    static uint8_t last_state = LV_INDEV_STATE_REL;
    static uint8_t long_pressed = 0;
    uint32_t txt_id = WATCH_TEXT_ID_KEY_RELEASED;

    if((last_event == arg->key_event) && (last_state == arg->data.state)) {
        return;
    }
    printf("%s: event=%d, state=%d\n", __func__, arg->key_event, arg->data.state);

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    if((NULL != ht_ext)
            && (HW_PRESS_KEY == ht_ext->module)
            && (NULL != ht_ext->label_key_state)) {
        if((KEY_EVENT_POWER_ON == arg->key_event)
                || (KEY_EVENT_LONG_PRESS == arg->key_event)) {
            txt_id = WATCH_TEXT_ID_KEY_LONG_PRESSED;
            long_pressed = 1;
        } else {
            if(LV_INDEV_STATE_PR == arg->data.state) {
                if(0 == long_pressed) {
                    txt_id = WATCH_TEXT_ID_KEY_PRESSED;
                } else {
                    txt_id = WATCH_TEXT_ID_KEY_LONG_PRESSED;
                }
            } else if((KEY_EVENT_CLICK == arg->key_event && LV_INDEV_STATE_REL == arg->data.state)
                      || (KEY_EVENT_RELEASE == arg->key_event && long_pressed)) {
                txt_id = WATCH_TEXT_ID_KEY_RELEASED;
                long_pressed = 0;
            }
        }

        lv_label_set_text_id(ht_ext->label_key_state, txt_id);
        if(WATCH_TEXT_ID_KEY_RELEASED == txt_id) {
            hardware_testing_result_create(lv_obj_get_parent(ht_ext->label_key_state), TEST_SUCCESS);
        }
    } else {
        lv_watch_go_back();
    }

    last_event = arg->key_event;
    last_state = arg->data.state;
}
#endif

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void hardware_testing_btn_rel_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        uint32_t num = lv_obj_get_user_data(btn).user_num;
        lv_obj_t * obj = NULL;

        obj = hardware_testing_item_watch_obj_create(NULL, engineer_mode_hardware_testing_list[num].item_prepare_destory);
        if(NULL == obj) {
            printf("%s: obj is null\n", __FUNCTION__);
        } else {
            engineer_mode_item_title_create(obj, engineer_mode_hardware_testing_list[num].txtId);
            engineer_mode_hardware_testing_list[num].item_content_create(obj);

            lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
            ht_ext->module = num;
        }
    }
}

static lv_obj_t * hardware_testing_startbtn_create(lv_obj_t * par, lv_event_cb_t event_cb)
{
    lv_obj_t * start_btn = lv_btn_create(par, NULL);
    lv_obj_set_size(start_btn, LV_HOR_RES * 2 / 3, 30);
    lv_obj_set_style_local_radius(start_btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 5);
    lv_obj_t * label = lv_label_create(start_btn, NULL);
    lv_label_set_text_id(label, WATCH_TEXT_ID_START_TEST);
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);
    lv_obj_align(start_btn, NULL, LV_ALIGN_IN_TOP_MID, 0, 80);
    lv_obj_add_protect(start_btn, LV_PROTECT_PRESS_LOST);
    lv_obj_set_event_cb(start_btn, event_cb);
    lv_watch_obj_add_element(start_btn);
    return start_btn;
}

lv_engineer_hardware_testing_obj_ext_t * hardware_testing_get_ext(void)
{
    lv_obj_t * activity_obj = lv_watch_get_activity_obj(ACT_ID_ENGINEER_MODE_HARDWARETESTING);

    //printf("%s watch_obj %p\n", __FUNCTION__, activity_obj);

    if(activity_obj) {
        lv_engineer_hardware_testing_obj_ext_t * ext = lv_obj_get_ext_attr(activity_obj);
        return ext;
    }

    return NULL;
}

static void hardware_testing_fail_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        uint32_t num = lv_obj_get_user_data(btn).user_num;

        if((HW_SPEAKER == num) || (HW_MICPHONE == num)) {
            if(HW_MICPHONE == num) {
                Hal_Tone_Play_End();
                lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
                uint32_t duration_ms;
                Hal_Record_Buffer_Stop_Req(&ht_ext->buffer_size, &duration_ms);
                if(NULL != ht_ext->buffer) {
                    LV_ASSERT_MEM(ht_ext->buffer);
                    ht_ext->buffer = NULL;
                }
            } else {
                Hal_NFFS_File_Play_End();
            }
        } else if(HW_CAMERA == num) {
            camera_destory();
        } else if(HW_BACKLIGHT == num) {
            setting_set_backlight_intensity(setting_get_backlight_intensity(), true);
        } else if(HW_VIBRATION == num) {
            Hal_Vibrator_Play_End();
        }

        hardware_testing_result_create(lv_obj_get_parent(btn), TEST_FAILED);
    }
}

static void hardware_testing_success_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        uint32_t num = lv_obj_get_user_data(btn).user_num;
        if((HW_SPEAKER == num) || (HW_MICPHONE == num)) {
            if(HW_MICPHONE == num) {
                Hal_Tone_Play_End();
                lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
                uint32_t duration_ms;
                Hal_Record_Buffer_Stop_Req(&ht_ext->buffer_size, &duration_ms);
                if(NULL != ht_ext->buffer) {
                    LV_ASSERT_MEM(ht_ext->buffer);
                    ht_ext->buffer = NULL;
                }
            } else {
                Hal_NFFS_File_Play_End();
            }
        } else if(HW_CAMERA == num) {
            camera_destory();
        } else if(HW_BACKLIGHT == num) {
            setting_set_backlight_intensity(setting_get_backlight_intensity(), true);
        } else if(HW_VIBRATION == num) {
            Hal_Vibrator_Play_End();
        }

        hardware_testing_result_create(lv_obj_get_parent(btn), TEST_SUCCESS);
    }
}

static void hardware_testing_resultbtn_create(lv_obj_t * par, uint8_t num)
{
    lv_engineer_main_obj_ext_t * ext = engineer_mode_get_ext();

    lv_obj_t * fail_btn = lv_btn_create(par, NULL);
    lv_obj_t * fail_label = lv_label_create(fail_btn, NULL);
    lv_obj_set_size(fail_btn, LV_HOR_RES / 2, LV_VER_RES / 7);
    lv_label_set_text_id(fail_label, WATCH_TEXT_ID_FAIL);
    lv_obj_set_event_cb(fail_btn, hardware_testing_fail_btn_event_cb);
    lv_obj_add_style(fail_btn, LV_BTN_PART_MAIN, &(ext->red_st));
    lv_obj_align(fail_btn, par, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
    lv_watch_set_free_num(fail_btn, num);

    lv_obj_t * suc_btn = lv_btn_create(par, fail_btn);
    lv_obj_t * suc_label = lv_label_create(suc_btn, NULL);
    lv_label_set_text_id(suc_label, WATCH_TEXT_ID_SUCCESS);
    lv_obj_set_event_cb(suc_btn, hardware_testing_success_btn_event_cb);
    lv_obj_add_style(suc_btn, LV_BTN_PART_MAIN, &(ext->green_st));
    lv_obj_align(suc_btn, fail_btn, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
    lv_watch_set_free_num(suc_btn, num);
}

static void hardware_testing_result_timer_func(void * param)
{
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->timer = NULL;

    if(false == hardware_testing_match_obj()) {
        return;
    }

    lv_obj_del((lv_obj_t *)param);
    lv_obj_del(lv_watch_get_top_activity_obj());
}

static void hardware_testing_result_create(lv_obj_t * par, engineer_mode_test_res_t res)
{
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    lv_engineer_main_obj_ext_t * ext = engineer_mode_get_ext();
    ht_ext->module = HW_MAX;

    lv_obj_clean(par);
    //lv_obj_del(lv_watch_get_top_activity_obj());

    lv_obj_t * bg = lv_cont_create(par, NULL);
    lv_obj_set_size(bg, LV_HOR_RES, LV_VER_RES);
    lv_cont_set_layout(bg, LV_LAYOUT_CENTER);

    lv_obj_t * label = lv_label_create(bg, NULL);
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font30);
    if(TEST_SUCCESS == res) {
        lv_obj_add_style(bg, LV_CONT_PART_MAIN, &ext->green_st);
        lv_label_set_text_id(label, WATCH_TEXT_ID_SUCCESS);
    } else {
        lv_obj_add_style(bg, LV_CONT_PART_MAIN, &ext->red_st);
        lv_label_set_text_id(label, WATCH_TEXT_ID_FAIL);
    }
    ht_ext->timer = Hal_Timer_Start(2000, hardware_testing_result_timer_func, bg, false);
}

static bool hardware_testing_match_obj(void)
{
    bool ret = true;

    if(NULL == lv_watch_get_activity_obj(ACT_ID_ENGINEER_MODE_MAIN)) {
        ret = false;
    }

    if(lv_watch_get_top_activity_obj() != lv_watch_get_activity_obj(ACT_ID_ENGINEER_MODE_ITEM_HWT)) {
        ret = false;
    }

    return ret;
}

static void emht_presskey_create(lv_obj_t * par)
{
    lv_obj_t * label = lv_label_create(par, NULL);
    lv_label_set_text_id(label, WATCH_TEXT_ID_KEY_RELEASED);
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);

    lv_obj_t * title = lv_obj_get_child_back(par, NULL);
    lv_obj_align(label, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 50);

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    if(NULL != ht_ext) {
        ht_ext->module = HW_PRESS_KEY;
        ht_ext->label_key_state = label;
    }
}

static void emht_touch_screen_create(lv_obj_t * par)
{
    hardware_testing_startbtn_create(par, touch_screen_start_btn_event_cb);
}

/* draw track of the pointer */
static void pointer_test_event_cb(lv_obj_t * obj, lv_event_t e)
{
    lv_engineer_hardware_testing_obj_ext_t * tp_pointer_ext = hardware_testing_get_ext();
    lv_point_t * point_list = tp_pointer_ext->point_list;

    if(LV_EVENT_PRESSED == e) {
        lv_obj_t * childobj = lv_obj_get_child(obj, NULL);

        while(childobj) {
            LV_ASSERT_MEM(lv_obj_get_user_data_ptr(childobj));
            lv_obj_del(childobj);
            childobj = lv_obj_get_child(obj, NULL);
        }

        lv_indev_t * indev = lv_indev_get_act();
        lv_indev_get_point(indev, point_list);

        tp_pointer_ext->tp_lable = lv_label_create(obj, NULL);
        lv_label_set_text(tp_pointer_ext->tp_lable, "");
        lv_obj_align(tp_pointer_ext->tp_lable, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 5);
    } else if(LV_EVENT_PRESSING == e) {
        lv_indev_t * indev = lv_indev_get_act();
        lv_indev_get_point(indev, &point_list[1]);

        if((point_list[0].x != point_list[1].x)
                || (point_list[0].y != point_list[1].y)) {
            lv_obj_t * line;
            char xy_value[40];

            line = lv_line_create(obj, NULL);
            lv_obj_set_style_local_line_color(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
            lv_obj_set_style_local_line_width(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 1);
            lv_point_t * line_point = (lv_point_t *)lv_mem_alloc(sizeof(tp_pointer_ext->point_list));
            lv_watch_set_free_ptr(line, line_point);
            memcpy(line_point, point_list, sizeof(tp_pointer_ext->point_list));
            lv_line_set_points(line, line_point, 2);
            lv_obj_align(line, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);

            snprintf(xy_value, 40, "x1:%u, y1:%u\nx2:%u, y2:%u",
                     point_list[0].x,
                     point_list[0].y,
                     point_list[1].x,
                     point_list[1].y);

            lv_label_set_text(tp_pointer_ext->tp_lable, xy_value);
            memcpy(point_list, &point_list[1], sizeof(lv_point_t));
        }
    } else if(LV_EVENT_CLICKED == e) {
        lv_obj_t * line;
        char xy_value[40];

        if((point_list[0].x == point_list[1].x)
                && (point_list[0].y == point_list[1].y)) {
            point_list[1].x += 1;
            point_list[1].y += 1;
            snprintf(xy_value, 40, "x1:%u, y1:%u\nx2:%u, y2:%u",
                     point_list[0].x,
                     point_list[0].y,
                     point_list[1].x - 1,
                     point_list[1].y - 1);
        } else {
            snprintf(xy_value, 40, "x1:%u, y1:%u\nx2:%u, y2:%u",
                     point_list[0].x,
                     point_list[0].y,
                     point_list[1].x,
                     point_list[1].y);
        }


        line = lv_line_create(obj, NULL);
        lv_obj_set_style_local_line_color(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
        lv_obj_set_style_local_line_width(line, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 1);
        lv_point_t * line_point = (lv_point_t *)lv_mem_alloc(sizeof(tp_pointer_ext->point_list));
        lv_watch_set_free_ptr(line, line_point);
        memcpy(line_point, point_list, sizeof(tp_pointer_ext->point_list));
        lv_line_set_points(line, line_point, 2);
        lv_obj_align(line, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);

        lv_label_set_text(tp_pointer_ext->tp_lable, xy_value);
    }
}

static void emht_tp_pointer_create(lv_obj_t * par)
{
    lv_engineer_hardware_testing_obj_ext_t * tp_pointer_ext = hardware_testing_get_ext();
    tp_pointer_ext->tp_content = lv_cont_create(par, NULL);

    lv_obj_t * content = tp_pointer_ext->tp_content;
    lv_obj_add_style(content, LV_CONT_PART_MAIN, &lv_style_pretty);
    lv_obj_set_style_local_bg_color(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_obj_set_style_local_bg_grad_color(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
    lv_obj_set_size(content, lv_obj_get_width(par), lv_obj_get_height(par));
    lv_obj_set_event_cb(content, pointer_test_event_cb);
    lv_obj_set_click(content, true);
}

static void touch_screen_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * par = lv_obj_get_parent(btn);

        lv_obj_t * cont = lv_cont_create(par, NULL);
        lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_watch_black_tight);
        lv_obj_set_style_local_bg_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_bg_grad_color(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
        lv_obj_set_style_local_radius(cont, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0);
        lv_cont_set_layout(cont, LV_LAYOUT_GRID);

        uint8_t i = 0;
        lv_obj_t * btn_block[TOUCH_SCR_TEST_LCD_AREA_CNT];
        for(i = 0; i < TOUCH_SCR_TEST_LCD_AREA_CNT; i++) {
            btn_block[i] = lv_btn_create(cont, NULL);
            lv_obj_set_size(btn_block[i], (LV_HOR_RES + 3) / 4, (LV_VER_RES + 5) / 7);
            lv_obj_add_style(btn_block[i], LV_BTN_PART_MAIN, &lv_watch_black_tight);
            lv_obj_set_style_local_border_width(btn_block[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 1);
            lv_obj_set_style_local_border_color(btn_block[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
            lv_obj_set_style_local_bg_color(btn_block[i], LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_GREEN);
            lv_obj_set_style_local_bg_grad_color(btn_block[i], LV_BTN_PART_MAIN, LV_STATE_PRESSED, LV_COLOR_GREEN);
            lv_obj_set_style_local_radius(btn_block[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 0);

            if(0 == i) {
                orignal_btn_signal = lv_obj_get_signal_cb(btn_block[i]);
            }
            lv_obj_set_signal_cb(btn_block[i], touch_screen_lcdarea_btn_signal);
        }
    }
}

static lv_res_t touch_screen_lcdarea_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
{
    if((LV_SIGNAL_PRESSED != sign) && (LV_SIGNAL_PRESS_LOST != sign) && (LV_SIGNAL_RELEASED != sign) && (LV_SIGNAL_CONTROL != sign)) {
        return (orignal_btn_signal(btn, sign, param));
    }

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = NULL;
    if(LV_SIGNAL_PRESSED == sign) {
        if(LV_BTN_STATE_RELEASED == lv_btn_get_state(btn)) {
            ht_ext = hardware_testing_get_ext();
            ht_ext->lcdarea_click_num++;
            lv_btn_set_state(btn, LV_BTN_STATE_PRESSED);
        }
    } else if((LV_SIGNAL_PRESS_LOST == sign) || (LV_SIGNAL_RELEASED == sign)) {
        lv_btn_set_state(btn, LV_BTN_STATE_PRESSED);
        ht_ext =  hardware_testing_get_ext();
        if(TOUCH_SCR_TEST_LCD_AREA_CNT == ht_ext->lcdarea_click_num) {
            lv_obj_t * par = lv_obj_get_parent(lv_obj_get_parent(btn));
            lv_obj_del(lv_obj_get_parent(btn));
            hardware_testing_result_create(par, TEST_SUCCESS);

            ht_ext->lcdarea_click_num = 0;
        }
    }
    return LV_RES_OK;
}

static void emht_display_create(lv_obj_t * par)
{
    hardware_testing_startbtn_create(par, display_start_btn_event_cb);
}

static void display_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * par = lv_obj_get_parent(btn);
        lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
        lv_engineer_main_obj_ext_t * ext = engineer_mode_get_ext();

        lv_obj_t * cont[6];
        uint8_t i = 0;
        lv_obj_clean(par);
        const lv_style_t * cont_style[5] = {
            &lv_style_pretty,
            &lv_watch_black_tight,
            &(ext->blue_st),
            &(ext->green_st),
            &(ext->red_st),
        };
        for(i = 0; i < 5; i++) {
            cont[i] = lv_cont_create(par, NULL);
            lv_obj_set_size(cont[i], LV_HOR_RES, LV_VER_RES);
            lv_obj_add_style(cont[i], LV_CONT_PART_MAIN, (lv_style_t *)cont_style[i]);
        }
        ht_ext->timer = Hal_Timer_Start(DISPLAY_TEST_LCD_COLOR_TIME_OUT, display_lcdcolor_timer_func, cont[0], true);
    }
}

static void display_lcdcolor_timer_func(void * param)
{
    if(false == hardware_testing_match_obj()) {
        return;
    }

    lv_obj_t * obj = (lv_obj_t *)param;
    lv_obj_t * par = lv_obj_get_parent(obj);
    lv_obj_t * child_obj = lv_obj_get_child(par, NULL);
    if(child_obj != obj) {
        lv_obj_del(lv_obj_get_child(par, NULL));
    } else {
        lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
        lv_obj_clean(par);
        display_test_result_create(par);
    }
}

static void display_test_result_create(lv_obj_t * par)
{
    lv_obj_t * title = engineer_mode_item_title_create(par, WATCH_TEXT_ID_LCDTEST_RESULT);

    lv_obj_t * label_tip = lv_label_create(par, NULL);
    lv_obj_add_style(label_tip, LV_LABEL_PART_MAIN, &lv_watch_font20);
    lv_label_set_long_mode(label_tip, LV_LABEL_LONG_BREAK);
    lv_obj_set_size(label_tip, LV_HOR_RES, LV_VER_RES / 4);
    lv_label_set_text_id(label_tip, WATCH_TEXT_ID_LCDTEST_TIP);
    lv_label_set_align(label_tip, LV_LABEL_ALIGN_CENTER);
    lv_obj_align(label_tip, title, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

    hardware_testing_resultbtn_create(par, HW_DISPLAY);
}

static void hwtest_camera_pre_select_btn_rel_action(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED != e) return;
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    printf("camera_lte %d\n", ht_ext->camera_lte_btn);
    lv_obj_t * img = lv_obj_get_child_back(btn, NULL);

    if(true == ht_ext->camera_lte_btn) {
        ht_ext->camera_lte_btn = false;
        lv_img_set_src(img, ICON_UNCHECK);
    } else {
        ht_ext->camera_lte_btn = true;
        lv_img_set_src(img, ICON_CHECK_TEST);
    }
}

static lv_obj_t * camera_pre_select_btn(lv_obj_t * par)
{
    lv_obj_t * btn = lv_btn_create(par, NULL);

    lv_obj_add_style(btn, LV_BTN_PART_MAIN,  &lv_watch_style_transp);
    lv_btn_set_layout(btn, LV_LAYOUT_ROW_MID);
    lv_obj_add_protect(btn, LV_PROTECT_PRESS_LOST);
    lv_watch_obj_add_element(btn);
    lv_obj_set_width(btn, LV_HOR_RES * 4 / 5);

    lv_obj_t * img = lv_img_create(btn, NULL);
    lv_img_set_src(img, ICON_UNCHECK);
    lv_obj_align(img, btn, LV_ALIGN_IN_LEFT_MID, 10, 0);

    lv_obj_t * label = lv_label_create(btn, NULL);
    //lv_obj_add_style(label, &lv_watch_font20);
    lv_label_set_text_id(label, WATCH_TEXT_ID_OPEN_CAMERA_LTE);
    lv_obj_align(label, img, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
    lv_obj_set_event_cb(btn, hwtest_camera_pre_select_btn_rel_action);
    return btn;
}

static void emht_camera_create(lv_obj_t * par)
{
    lv_obj_t * start_btn = hardware_testing_startbtn_create(par, camera_start_btn_event_cb);
    lv_obj_t * pre_sel_btn = camera_pre_select_btn(par);
    lv_obj_align(pre_sel_btn, start_btn, LV_ALIGN_OUT_BOTTOM_MID, 0, 40);
}

static void ltepower_test_task(lv_task_t * task)
{
    int8_t i;
    MMI_Modem_Set_Band_Req_t * band_info = NULL;
    lv_engineer_hardware_testing_obj_ext_t * cameraext = hardware_testing_get_ext();

    band_info = (MMI_Modem_Set_Band_Req_t *)Hal_Mem_Alloc(sizeof(MMI_Modem_Set_Band_Req_t));
    Hal_Mem_Set(band_info, 0, sizeof(MMI_Modem_Set_Band_Req_t));

    app_adaptor_get_lte_band_req(MMI_MODEM_SIM_1, band_info);
    // printf("%s,lteBandH=0x%x,lteBandL=0x%x,cameraext->lteband_count=%d \n", __FUNCTION__,
    //     band_info->lteBandH,band_info->lteBandL,cameraext->lteband_count);
    for(i = cameraext->lteband_count; i < (LTE_BANDH_LIST_CNT + LTE_BANDL_LIST_CNT); i++) {
        //printf("i=%d \n",i);
        if(i < LTE_BANDH_LIST_CNT) {
            if(band_info->lteBandH & lte_bandh_list[i][1]) {
                // AT+LTEPOWER=0，lte_bandh_list[i][0]，0
                app_adaptor_lte_power_tx_req(MMI_MODEM_SIM_1, 0, lte_bandh_list[i][0], 1);
                i++;
                break;
            }
        } else if(i >= LTE_BANDH_LIST_CNT) {
            if(band_info->lteBandL & lte_bandl_list[i - LTE_BANDH_LIST_CNT][1]) {
                // AT+LTEPOWER=0，lte_bandl_list[i-LTE_BANDH_LIST_CNT][0]，0
                app_adaptor_lte_power_tx_req(MMI_MODEM_SIM_1, 0, lte_bandl_list[i - LTE_BANDH_LIST_CNT][0], 1);
                i++;
                break;
            }

        }
    }
    cameraext->lteband_count = i;
    if(cameraext->lteband_count >= (LTE_BANDH_LIST_CNT + LTE_BANDL_LIST_CNT)) {
        cameraext->lteband_count = 0;
    }
    Hal_Mem_Free(band_info);
}

static void camera_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * par = lv_obj_get_parent(btn);
        lv_obj_t * cont = lv_cont_create(par, NULL);
        lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &(lv_watch_black_tight));

        cam_start_preview_t cam_params;

        cam_params.width = 240;
        cam_params.height = 240;
        cam_params.sensor_id = 0;
        Hal_Camera_Start_Preview(&cam_params);

        lv_engineer_hardware_testing_obj_ext_t * cameraext = hardware_testing_get_ext();
        cameraext->img_camera.header.always_zero = 0;
        cameraext->img_camera.header.w = lv_obj_get_width(lv_obj_get_parent(cont));
        cameraext->img_camera.header.h = lv_obj_get_height(lv_obj_get_parent(cont));
        cameraext->img_camera.data_size = cameraext->img_camera.header.w * cameraext->img_camera.header.h * LV_COLOR_SIZE / 8;
        cameraext->img_camera.header.cf = LV_IMG_CF_TRUE_COLOR;
        cameraext->img_camera.data = lv_mem_alloc(cameraext->img_camera.header.w * cameraext->img_camera.header.h * LV_COLOR_SIZE / 8);
        LV_ASSERT_MEM(cameraext->img_camera.data);
        if(NULL == cameraext->img_camera.data) {
            printf("%s: camera.data is null\n", __FUNCTION__);
            return;
        }

        memset((void *)cameraext->img_camera.data, 0, cameraext->img_camera.header.w * cameraext->img_camera.header.h * LV_COLOR_SIZE / 8);
        lv_obj_t * img = lv_img_create(cont, NULL);
        lv_img_cache_invalidate_src(&cameraext->img_camera);
        lv_img_set_src(img, &cameraext->img_camera);

        cameraext->camera_preview_task = lv_task_create(camera_preview_task, 100, LV_TASK_PRIO_HIGH, (void *)img);

        lv_obj_t * label = lv_label_create(cont, NULL);
        lv_label_set_text_id(label, WATCH_TEXT_ID_CAMERA_TEST);
        lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20_yellow);
        lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 5);

        if(true == cameraext->camera_lte_btn) {
            cameraext->lteband_count = 0;
            //close simcheck_task
            app_adp_radio_power_req(0);  //cfun 0

            lv_obj_t * ltepower_label = lv_label_create(cont, NULL);
            lv_label_set_text(ltepower_label, "LTEPOWER testing");
            lv_obj_add_style(ltepower_label, LV_LABEL_PART_MAIN, &lv_watch_font20_gray);
            lv_obj_align(ltepower_label, label, LV_ALIGN_IN_TOP_MID, 0, 24);
            cameraext->ltepower_test_task = lv_task_create(ltepower_test_task, 600, LV_TASK_PRIO_MID, (void *)img);
        }
        hardware_testing_resultbtn_create(par, HW_CAMERA);
    }
}

static void camera_preview_task(lv_task_t * task)
{
    if(false == hardware_testing_match_obj()) {
        return;
    }

    lv_engineer_hardware_testing_obj_ext_t * cameraext = hardware_testing_get_ext();
    if(Hal_Camera_Preview((uint8_t *)cameraext->img_camera.data)) {
        //update the src of img.
        lv_obj_t * img = (lv_obj_t *)task->user_data;
        lv_img_set_src(img, &cameraext->img_camera);
    }
    lv_task_set_period(cameraext->camera_preview_task, 30);
}

static void camera_destory(void)
{
    lv_engineer_hardware_testing_obj_ext_t * cameraext = hardware_testing_get_ext();
    Hal_Camera_Stop_Preview(0);
    if(NULL != cameraext->ltepower_test_task) {
        app_adaptor_lte_power_tx_req(MMI_MODEM_SIM_1, 0, 1, 9);
        app_adp_radio_power_req(1);
        lv_task_del(cameraext->ltepower_test_task);
        cameraext->ltepower_test_task = NULL;
    }
    if(NULL != cameraext->img_camera.data) {
        lv_mem_free(cameraext->img_camera.data);
        cameraext->img_camera.data = NULL;
    }
    if(NULL != cameraext->camera_preview_task) {
        lv_task_del(cameraext->camera_preview_task);
        cameraext->camera_preview_task = NULL;
    }
    cameraext->camera_lte_btn = false;
}

static void emht_speaker_create(lv_obj_t * par)
{
    hardware_testing_startbtn_create(par, speaker_start_btn_event_cb);
}

static void speaker_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * label_tip  = lv_obj_get_child(btn, NULL);
        // play tone
        Hal_NFFS_File_Play_Onetime(AUDIO_INCOMING_CALL, query_current_volume(), NULL, NULL);
        lv_label_set_text_id(label_tip, WATCH_TEXT_ID_STOP_TEST);
        lv_obj_set_event_cb(btn, speaker_stop_btn_event_cb);

        lv_obj_t * par = lv_obj_get_parent(btn);

        hardware_testing_resultbtn_create(par, HW_SPEAKER);

        lv_obj_t * label = lv_label_create(par, NULL);
        lv_label_set_text_id(label, WATCH_TEXT_ID_MUSIC_PLAYING);
        lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
        lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
        lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);
        lv_obj_set_width(label, LV_HOR_RES);
        lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 35);
    }
}

static void speaker_stop_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        Hal_NFFS_File_Play_End();
        lv_obj_del(lv_obj_get_child(lv_obj_get_parent(btn), NULL));
        lv_label_set_text_id(lv_obj_get_child(btn, NULL), WATCH_TEXT_ID_START_TEST);
        lv_obj_set_event_cb(btn, speaker_start_btn_event_cb);
    }
}

static void emht_micphone_create(lv_obj_t * par)
{
    hardware_testing_startbtn_create(par, micphone_start_btn_event_cb);
}

static void micphone_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();

        // lv_btn_set_state(btn, LV_BTN_STATE_DISABLED);
        lv_obj_set_hidden(btn, true);
        lv_obj_t * par = lv_obj_get_parent(btn);

        hardware_testing_resultbtn_create(par, HW_MICPHONE);

        lv_obj_t * label = lv_label_create(par, NULL);
        char * txt1 = (char *)lv_lang_get_text(WATCH_TEXT_ID_MICPHONE_RECORDING);
        char * txt2 = (char *)lv_lang_get_text(WATCH_TEXT_ID_SECONDS);
        char text[50] = {};

        if(LANG_EN == lv_lang_act()) {
            snprintf(text, 50, "%s %d%s", txt1, MIC_RECORD_MAX_RECORD_DURATION, txt2);
        } else if(LANG_CH == lv_lang_act()) {
            snprintf(text, 50, "%s%d%s", txt1, MIC_RECORD_MAX_RECORD_DURATION, txt2);
        }

        lv_label_set_text(label, text);
        lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
        lv_obj_set_width(label, LV_HOR_RES);
        lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
        lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);
        lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 35);

        ht_ext->label_key_state = label;
        ht_ext->buffer_size = 0;
        ht_ext->buffer = (uint8_t *)lv_mem_alloc(MIC_RECORD_MAX_RECORD_SIZE);

        Hal_Record_Buffer_Start_Req(ht_ext->buffer,
                                    MIC_RECORD_MAX_RECORD_SIZE,
                                    MIC_RECORD_MAX_RECORD_DURATION * 1000,
                                    ht_micphone_record_cb);
    }
}

static void ht_micphone_record_play_over_cb(void * para)
{
    if(NULL == para) return;

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = (lv_engineer_hardware_testing_obj_ext_t *)para;
    ht_ext->buffer_size = 0;
    if(NULL != ht_ext->buffer) {
        LV_ASSERT_MEM(ht_ext->buffer);
        ht_ext->buffer = NULL;
    }
    lv_obj_t * par = lv_obj_get_parent(ht_ext->label_key_state);
    lv_obj_del(ht_ext->label_key_state);

    lv_obj_t * btn = lv_obj_get_child_back(par, lv_obj_get_child_back(par, NULL));
    lv_btn_set_state(btn, LV_BTN_STATE_RELEASED);
    lv_obj_set_hidden(btn, false);
    lv_label_set_text_id(lv_obj_get_child(btn, NULL), WATCH_TEXT_ID_RETEST);
}

static void ht_micphone_record_task_cb(lv_task_t * task)
{
    uint32_t duration_ms;

    if(NULL == task) {
        return;
    }

    if(false == hardware_testing_match_obj()) {
        return;
    }

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = (lv_engineer_hardware_testing_obj_ext_t *)task->user_data;

    switch(ht_ext->event) {
        case MCI_EVENT_EOS:
            lv_label_set_text_id(ht_ext->label_key_state, WATCH_TEXT_ID_MICPHONE_RECORD_CHECK);
            Hal_Record_Buffer_Stop_Req(&ht_ext->buffer_size, &duration_ms);
            Hal_Tone_Play_Onetime((uint32_t *)ht_ext->buffer, ht_ext->buffer_size, query_current_volume(), ht_micphone_record_play_over_cb, ht_ext);
            break;
        case MCI_EVENT_ERROR:
            /*recoder stop if value is - 996*/
            ht_ext->buffer_size = 0;
            if(NULL != ht_ext->buffer) {
                LV_ASSERT_MEM(ht_ext->buffer);
                ht_ext->buffer = NULL;
            }
            break;
        case MCI_EVENT_INFO:
            break;
        default:
            break;
    }
    ht_ext->record_task = NULL;
}

static void ht_micphone_record_cb(MCI_EVNET_T event, MCI_INFO_T info_type, int32_t value)
{
    printf("----------------------event %d, type %d, value %d in ht_micphone_record_cb\n",
           event, info_type, value);

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    if(NULL == ht_ext) {
        return;
    }

    ht_ext->event = event;
    ht_ext->info_type = info_type;
    ht_ext->value = value;
    if((MCI_EVENT_EOS == event) || (MCI_EVENT_ERROR == event)) {
        ht_ext->record_task = lv_task_create(ht_micphone_record_task_cb, 10, LV_TASK_PRIO_MID, ht_ext);
        lv_task_once(ht_ext->record_task);
    }
}

static void emht_memory_create(lv_obj_t * par)
{
    lv_mem_monitor_t mon;
    char str[32];
    char mem_value[10];
    float total = 0.0f;
    float free = 0.0f;

    memset(str, 0, 32);
    memset(mem_value, 0, 10);
    lv_mem_monitor(&mon);
    total = mon.total_size / 1024;
    free = mon.free_size / 1024;

    lv_obj_t * label_t = lv_label_create(par, NULL);
    lv_obj_add_style(label_t, LV_LABEL_PART_MAIN, &lv_watch_font20);
    gcvt(total, 6, mem_value);
    snprintf(str, 32, "%s: %sKB ", (char *)lv_lang_get_text(WATCH_TEXT_ID_MEM_TOTAL), mem_value);
    lv_label_set_text(label_t, str);
    lv_obj_align(label_t, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 50);

    lv_obj_t * label_free = lv_label_create(par, label_t);
    memset(str, 0, 32);
    memset(mem_value, 0, 10);
    gcvt(free, 6, mem_value);
    snprintf(str, 32, "%s: %sKB", (char *)lv_lang_get_text(WATCH_TEXT_ID_MEM_FREE), mem_value);
    lv_label_set_text(label_free, str);
    lv_obj_align(label_free, label_t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 10);

    hardware_testing_resultbtn_create(par, HW_MEMORY);
}

static void emht_backlight_create(lv_obj_t * par)
{
    hardware_testing_startbtn_create(par, backlight_start_btn_event_cb);
}

static void backlight_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * par = lv_obj_get_parent(btn);

        lv_obj_t * cont = lv_cont_create(par, NULL);
        lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
        lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_style_pretty);

        lv_anim_path_t path;
        lv_anim_path_init(&path);
        lv_anim_path_set_cb(&path, lv_anim_path_step);

        lv_anim_t a;
        lv_anim_init(&a);
        lv_anim_set_var(&a, cont);
        lv_anim_set_start_cb(&a, (lv_anim_ready_cb_t)backlight_change_anim);
        lv_anim_set_time(&a, 1);
        lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
        lv_anim_set_repeat_delay(&a, 3000);
        lv_anim_set_delay(&a, 1000);
        lv_anim_start(&a);

        lv_obj_del(btn);

        hardware_testing_resultbtn_create(par, HW_BACKLIGHT);
    }
}

static void backlight_change_anim(lv_anim_t * anim)
{
    static HAL_INTENSITY_LEVEL level =  HAL_INTENSITY_LEVEL_1;
    Hal_Backlight_Intensity_Set(level);
    level ++;
    if(HAL_INTENSITY_LEVEL_5 < level)
        level =  HAL_INTENSITY_LEVEL_1;
}

static void emht_gravity_create(lv_obj_t * par)
{
    lv_obj_t * label = lv_label_create(par, NULL);
    lv_label_set_text_id(label, WATCH_TEXT_ID_FLIP_WATCH);
    lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
    lv_obj_set_width(label, LV_HOR_RES);
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);
    lv_obj_align(label, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 10, -50);

    hardware_testing_resultbtn_create(par, HW_GRAVITY);
}

static void emht_battery_create(lv_obj_t * par)
{
    char str[64];
    battery_values_t bat_val;
    uint8_t bat_percent =  Hal_Battery_Get_Status();

    Hal_Mem_Set(&bat_val, 0, sizeof(battery_values_t));
    Hal_Battery_Get_Values(&bat_val);

    lv_obj_t * label_chg = lv_label_create(par, NULL);
    lv_obj_add_style(label_chg, LV_LABEL_PART_MAIN, &lv_watch_font20);
    lv_obj_align(label_chg, NULL, LV_ALIGN_IN_TOP_LEFT, 10, 40);

    // period update
    lv_anim_path_t path;
    lv_anim_path_init(&path);
    lv_anim_path_set_cb(&path, lv_anim_path_step);

    lv_anim_t a;
    lv_anim_init(&a);
    lv_anim_set_var(&a, label_chg);
    lv_anim_set_start_cb(&a, (lv_anim_ready_cb_t)battery_charging_status_update);
    lv_anim_set_time(&a, 1);
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_repeat_delay(&a, 500);  // udpate every 500ms
    lv_anim_set_delay(&a, 500);

    lv_anim_start(&a);

    lv_obj_t * label_vol = lv_label_create(par, label_chg);
    memset(str, 0, 64);
    snprintf(str, 64, "%s %dmv", (char *)lv_lang_get_text(WATCH_TEXT_ID_BAT_VOL), bat_val.battery_val_mV);
    lv_label_set_text(label_vol, str);
    lv_obj_align(label_vol, label_chg, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 10);

    lv_obj_t * label_temp = lv_label_create(par, label_chg);
    memset(str, 0, 64);
    snprintf(str, 64, "%s %d", (char *)lv_lang_get_text(WATCH_TEXT_ID_BAT_TEMP), bat_val.battery_temp);
    lv_label_set_text(label_temp, str);
    lv_obj_align(label_temp, label_vol, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 10);

    lv_obj_t * label_per = lv_label_create(par, label_chg);
    memset(str, 0, 64);
    snprintf(str, 64, "%s %d", (char *)lv_lang_get_text(WATCH_TEXT_ID_BAT_PERC),  bat_percent);
    lv_label_set_text(label_per, str);
    lv_obj_align(label_per, label_temp, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 10);

    lv_obj_t * label_sta = lv_label_create(par, label_chg);
    memset(str, 0, 64);
    snprintf(str, 64, "%s %s", (char *)lv_lang_get_text(WATCH_TEXT_ID_BAT_STA), (char *)lv_lang_get_text(WATCH_TEXT_ID_NORMAL));
    lv_label_set_text(label_sta, str);
    lv_obj_align(label_sta, label_per, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 10);

    hardware_testing_resultbtn_create(par, HW_BATTERY);
}

static void battery_charging_status_update(lv_anim_t * anim)
{
    char str[64];
    memset(str, 0, 64);
    if(HAL_CHG_DISCONNECTED == Hal_Charger_Get_Status()) {
        snprintf(str, 64, "%s %s", (char *)lv_lang_get_text(WATCH_TEXT_ID_CHG_STA), (char *)lv_lang_get_text(WATCH_TEXT_ID_UNCHG));
    } else {
        snprintf(str, 64, "%s %s", (char *)lv_lang_get_text(WATCH_TEXT_ID_CHG_STA), (char *)lv_lang_get_text(WATCH_TEXT_ID_CHARGING));
    }
    lv_label_set_text(anim->var, str);
}

static void emht_vibration_create(lv_obj_t * par)
{
    hardware_testing_startbtn_create(par, vibration_start_btn_event_cb);
}

static void vibration_start_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        // play tone
        Hal_Vibrator_Play_Repeat();

        lv_label_set_text_id(lv_obj_get_child(btn, NULL), WATCH_TEXT_ID_STOP_TEST);
        lv_obj_set_event_cb(btn, vibration_stop_btn_event_cb);

        lv_obj_t * par = lv_obj_get_parent(btn);

        hardware_testing_resultbtn_create(par, HW_VIBRATION);

        lv_obj_t * label = lv_label_create(par, NULL);
        lv_label_set_text_id(label, WATCH_TEXT_ID_VIBRATION_PLAYING);
        lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
        lv_obj_set_width(label, LV_HOR_RES);
        lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
        lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);
        lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 35);
    }
}

static void vibration_stop_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        Hal_Vibrator_Play_End();
        lv_obj_del(lv_obj_get_child(lv_obj_get_parent(btn), NULL));
        lv_label_set_text_id(lv_obj_get_child(btn, NULL), WATCH_TEXT_ID_START_TEST);
        lv_obj_set_event_cb(btn, vibration_start_btn_event_cb);
    }
}

static void emht_alarm_create(lv_obj_t * par)
{
    lv_obj_t * btn = hardware_testing_startbtn_create(par, alarm_setting_btn_event_cb);
    lv_obj_t * label = lv_obj_get_child(btn, NULL);
    lv_label_set_text_id(label, WATCH_TEXT_ID_EMODE_HW_ALARM_SETTINE);
    lv_watch_set_free_num(btn, 0);
    lv_obj_set_y(btn, 30);
    lv_engineer_hardware_testing_obj_ext_t * ext = hardware_testing_get_ext();

    ext->date_label = lv_label_create(par, NULL);
    lv_obj_add_style(ext->date_label, LV_LABEL_PART_MAIN, &lv_watch_font30);
    lv_label_set_text(ext->date_label, "");

    ext->time_label = lv_label_create(par, ext->date_label);
}

static void alarm_get_yearopt_from_year(uint16_t year, char * yearopt)
{
    uint16_t year_display[5];
    uint8_t  i, pos = 0;

    year = year < ALARM_SETTING_TIME_MIN_YEAR ? ALARM_SETTING_TIME_MIN_YEAR : year;
    year = year > ALARM_SETTING_TIME_MAX_YEAR ? ALARM_SETTING_TIME_MAX_YEAR : year;
    // Create year roller options
    year_display[0] = ((year - ALARM_SETTING_TIME_MIN_YEAR + ALARM_SETTING_TIME_YEAR_LOOP_CNT) - 2) % ALARM_SETTING_TIME_YEAR_LOOP_CNT + ALARM_SETTING_TIME_MIN_YEAR;
    year_display[1] = ((year - ALARM_SETTING_TIME_MIN_YEAR + ALARM_SETTING_TIME_YEAR_LOOP_CNT) - 1) % ALARM_SETTING_TIME_YEAR_LOOP_CNT + ALARM_SETTING_TIME_MIN_YEAR;
    year_display[2] = year;
    year_display[3] = (year + 1 - ALARM_SETTING_TIME_MIN_YEAR) % ALARM_SETTING_TIME_YEAR_LOOP_CNT + ALARM_SETTING_TIME_MIN_YEAR;
    year_display[4] = (year + 2 - ALARM_SETTING_TIME_MIN_YEAR) % ALARM_SETTING_TIME_YEAR_LOOP_CNT + ALARM_SETTING_TIME_MIN_YEAR;

    for(i = 0; i < 5; i++) {
        yearopt[pos++] = year_display[i] / 1000 + 0x30;
        yearopt[pos++] = (year_display[i] % 1000) / 100 + 0x30;
        yearopt[pos++] = (year_display[i] % 100) / 10 + 0x30;
        yearopt[pos++] = year_display[i] % 10 + 0x30;
        yearopt[pos++] = 0x0A;
    }
    yearopt [pos - 1] = 0;
}

static void alarm_get_optstr_from_num(uint8_t num, uint8_t num2, char * stropt, uint8_t type, uint8_t leapyear)
{
    uint8_t opt_display[5];
    uint8_t i, pos = 0;
    uint8_t min = 1;
    uint8_t max = 0;
    uint8_t count = 0;
    if(type == 1) { //month
        max = 12;
        count = 12;
    } else if(type == 2) { //hour
        max = 23;
        min = 0;
        count = 24;
    } else if(type == 3) { //min&sec
        min = 0;
        max = 59;
        count = 60;
    } else if(type == 4) { //day
        max = alarm_get_daycnt_from_month(num2, leapyear);
        count = max;

    }

    opt_display[0] = ((num - min + count) - 2) % count + min;
    opt_display[1] = ((num - min + count) - 1) % count + min;
    opt_display[2] = num;
    opt_display[3] = (num + 1 - min) % count + min;
    opt_display[4] = (num + 2 - min) % count + min;


    for(i = 0; i < 5; i++) {
        stropt[pos++] = (opt_display[i] % 100) / 10 + 0x30;
        stropt[pos++] = opt_display[i] % 10 + 0x30;
        stropt[pos++] = 0x0A;
    }
    stropt [pos - 1] = 0;

}

static uint8_t alarm_get_daycnt_from_month(uint8_t month, uint8_t leapyear)
{
    uint8_t daycnt = 0;
    if(month == 2) {
        if(leapyear == 1) {
            daycnt = 29;
        } else {
            daycnt = 28;
        }

    } else if((month == 4) || (month == 6) || (month == 9) || (month == 11)) {
        daycnt = 30;
    } else {
        daycnt = 31;
    }

    return daycnt;
}

static uint8_t alarm_isleapyear(uint32_t year)
{
    uint8_t leapyearflag = 0;

    if(year % 400 == 0) {
        leapyearflag = 1;
    } else {
        if((year % 4 == 0) && (year % 100 != 0)) {
            leapyearflag = 1;
        }
    }
    return(leapyearflag);
}

static void alarm_date_roller_event_cb(lv_obj_t * roller, lv_event_t e)
{
    char sel_str[6];
    char year_opt[32];
    char day_opt[16];
    char mon_opt[16];
    uint16_t year;
    uint8_t day;
    uint8_t new_day;
    uint8_t month;
    lv_obj_t * roller_day;
    lv_obj_t * roller_month;
    uint8_t leapyear = 0;

    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();

    if(LV_EVENT_VALUE_CHANGED != e) return;

    memset(sel_str, 0, 6);
    memset(year_opt, 0, 32);
    memset(day_opt, 0, 16);
    memset(mon_opt, 0, 16);

    lv_roller_get_selected_str(roller, sel_str, 6);
    //printf("date roller action sel_str = %s\n",sel_str);

    if(lv_obj_get_user_data(roller).user_num == 1) {
        year = atoi(sel_str);
        alarm_get_yearopt_from_year(year, year_opt);
        lv_roller_set_options(roller, year_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller, 2, false);
        ht_ext->leapyear = alarm_isleapyear(year);
    } else if(lv_obj_get_user_data(roller).user_num == 2) {
        month = atoi(sel_str);
        alarm_get_optstr_from_num(month, 0, mon_opt, 1, 0);
        lv_roller_set_options(roller, mon_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller, 2, false);

        roller_day = ht_ext->roller[2];
        memset(sel_str, 0, 6);
        lv_roller_get_selected_str(roller_day, sel_str, 6);
        day = atoi(sel_str);
        leapyear = ht_ext->leapyear;
        new_day = alarm_get_daycnt_from_month(month, leapyear);
        if(new_day < day) day = new_day;

        alarm_get_optstr_from_num(day, month, day_opt, 4, leapyear);
        lv_roller_set_options(roller_day, day_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller_day, 2, false);
    } else if(lv_obj_get_user_data(roller).user_num == 3) {
        day = atoi(sel_str);
        roller_month = ht_ext->roller[1];
        memset(sel_str, 0, 6);
        lv_roller_get_selected_str(roller_month, sel_str, 6);
        month = atoi(sel_str);
        leapyear = ht_ext->leapyear;
        alarm_get_optstr_from_num(day, month, day_opt, 4, leapyear);
        lv_roller_set_options(roller, day_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller, 2, false);
    }
}

static void alarm_time_roller_event_cb(lv_obj_t * roller, lv_event_t e)
{
    char sel_str[4];
    char hour_opt[16];
    char min_opt[16];
    char sec_opt[16];
    uint8_t hour;
    uint8_t min;
    uint8_t sec;

    if(LV_EVENT_VALUE_CHANGED != e) return;

    memset(sel_str, 0, 4);
    memset(hour_opt, 0, 16);
    memset(min_opt, 0, 16);
    memset(sec_opt, 0, 16);

    lv_roller_get_selected_str(roller, sel_str, 4);

    if(lv_obj_get_user_data(roller).user_num == 1) {
        hour = atoi(sel_str);
        alarm_get_optstr_from_num(hour, 0, hour_opt, 2, 0);
        lv_roller_set_options(roller, hour_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller, 2, false);

    } else if(lv_obj_get_user_data(roller).user_num == 2) {
        min = atoi(sel_str);
        alarm_get_optstr_from_num(min, 0, min_opt, 3, 0);
        lv_roller_set_options(roller, min_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller, 2, false);

    } else if(lv_obj_get_user_data(roller).user_num == 3) {
        sec = atoi(sel_str);
        alarm_get_optstr_from_num(sec, 0, sec_opt, 3, 0);
        lv_roller_set_options(roller, sec_opt, LV_ROLLER_MODE_NORMAL);
        lv_roller_set_selected(roller, 2, false);
    }
}

static lv_obj_t * alarm_date_time_roller_create(lv_obj_t * par, uint8_t type, hal_rtc_t * date_time)
{
    lv_obj_t * content;
    lv_obj_t * roller1_cont;
    lv_obj_t * roller2_cont;
    lv_obj_t * roller3_cont;
    lv_obj_t * roller1;
    lv_obj_t * roller2;
    lv_obj_t * roller3;
    lv_obj_t * label1;
    lv_obj_t * label2;

    uint8_t leapyear = 0;
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();

    lv_obj_t * label = lv_label_create(par, NULL);
    if(type == 1)
        lv_label_set_text_id(label, WATCH_TEXT_ID_DATE_SETTING);
    else
        lv_label_set_text_id(label, WATCH_TEXT_ID_TIME_SETTING);
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20_gray);
    lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
    lv_obj_set_height(label, 40);
    lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);

    content =  lv_cont_create(par, NULL);
    lv_obj_set_size(content, LV_HOR_RES, LV_VER_RES / 2);
    lv_obj_set_pos(content, 0, lv_obj_get_height(label));
    lv_cont_set_layout(content, LV_LAYOUT_ROW_MID);
    lv_obj_add_style(content, LV_CONT_PART_MAIN, &lv_style_transp);
    lv_obj_set_style_local_pad_top(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 2);
    lv_obj_set_style_local_pad_bottom(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 2);
    lv_obj_set_style_local_pad_left(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 15);
    lv_obj_set_style_local_pad_right(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 15);
    lv_obj_set_style_local_pad_inner(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5);
    lv_obj_align(content, label, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);

    /*roller1 year or hour*/
    roller1_cont = lv_cont_create(content, NULL);
    lv_obj_set_size(roller1_cont, LV_HOR_RES / 4, LV_VER_RES / 2);
    lv_cont_set_layout(roller1_cont, LV_LAYOUT_OFF);
    lv_obj_add_style(roller1_cont, LV_CONT_PART_MAIN, &lv_watch_style_transp);

    roller1 = lv_roller_create(roller1_cont, NULL);
    ht_ext->roller[0] = roller1;
    lv_obj_add_style(roller1, LV_ROLLER_PART_BG, &lv_watch_font20_gray);
    lv_obj_set_style_local_text_line_space(roller1, LV_ROLLER_PART_BG, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_bg_opa(roller1, LV_ROLLER_PART_BG, LV_STATE_DEFAULT, LV_OPA_TRANSP);
    lv_obj_add_style(roller1, LV_ROLLER_PART_SELECTED, &lv_watch_font20_gray);
    lv_obj_set_style_local_text_line_space(roller1, LV_ROLLER_PART_SELECTED, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_bg_opa(roller1, LV_ROLLER_PART_SELECTED, LV_STATE_DEFAULT, LV_OPA_TRANSP);
    lv_roller_set_visible_row_count(roller1, 3);

    /*label1 - or :*/
    label1 = lv_label_create(content, NULL);
    lv_obj_set_style_local_text_font(label1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_THEME_WATCH_NIGHT_FONT_BIG);
    lv_obj_set_style_local_text_color(label1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE);

    /*roller2 month or minute*/
    roller2_cont = lv_cont_create(content, roller1_cont);
    roller2 = lv_roller_create(roller2_cont, NULL);
    ht_ext->roller[1] = roller2;
    lv_obj_add_style(roller2, LV_ROLLER_PART_BG, &lv_watch_font20_gray);
    lv_obj_set_style_local_text_line_space(roller2, LV_ROLLER_PART_BG, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_bg_opa(roller2, LV_ROLLER_PART_BG, LV_STATE_DEFAULT, LV_OPA_TRANSP);
    lv_obj_add_style(roller2, LV_ROLLER_PART_SELECTED, &lv_watch_font20_gray);
    lv_obj_set_style_local_text_line_space(roller2, LV_ROLLER_PART_SELECTED, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_bg_opa(roller2, LV_ROLLER_PART_SELECTED, LV_STATE_DEFAULT, LV_OPA_TRANSP);
    lv_roller_set_visible_row_count(roller2, 3);

    /*label1 - or :*/
    label2 = lv_label_create(content, label1);

    /*roller3 day or second*/
    roller3_cont = lv_cont_create(content, roller1_cont);
    roller3 = lv_roller_create(roller3_cont, NULL);
    ht_ext->roller[2] = roller3;
    lv_obj_add_style(roller3, LV_ROLLER_PART_BG, &lv_watch_font20_gray);
    lv_obj_set_style_local_text_line_space(roller3, LV_ROLLER_PART_BG, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_bg_opa(roller3, LV_ROLLER_PART_BG, LV_STATE_DEFAULT, LV_OPA_TRANSP);
    lv_obj_add_style(roller3, LV_ROLLER_PART_SELECTED, &lv_watch_font20_gray);
    lv_obj_set_style_local_text_line_space(roller3, LV_ROLLER_PART_SELECTED, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_bg_opa(roller3, LV_ROLLER_PART_SELECTED, LV_STATE_DEFAULT, LV_OPA_TRANSP);
    lv_roller_set_visible_row_count(roller3, 3);

    lv_watch_set_free_num(roller1, 1);
    lv_watch_set_free_num(roller2, 2);
    lv_watch_set_free_num(roller3, 3);

    /*set date*/
    if(type == 1) {
        char year_opt[32];
        char day_opt[16];
        char mon_opt[16];

        ht_ext->leapyear = alarm_isleapyear(date_time->tm_year);
        leapyear = ht_ext->leapyear;

        memset(day_opt, 0, 16);
        memset(mon_opt, 0, 16);
        memset(year_opt, 0, 32);

        alarm_get_yearopt_from_year(date_time->tm_year, year_opt);
        alarm_get_optstr_from_num(date_time->tm_mon, 0, mon_opt, 1, 0);
        alarm_get_optstr_from_num(date_time->tm_mday, date_time->tm_mon, day_opt, 4, leapyear);

        lv_roller_set_options(roller1, year_opt, LV_ROLLER_MODE_NORMAL);
        lv_obj_set_event_cb(roller1, alarm_date_roller_event_cb);

        lv_roller_set_options(roller2, mon_opt, LV_ROLLER_MODE_NORMAL);
        lv_obj_set_event_cb(roller2, alarm_date_roller_event_cb);

        lv_roller_set_options(roller3, day_opt, LV_ROLLER_MODE_NORMAL);
        lv_obj_set_event_cb(roller3, alarm_date_roller_event_cb);

        lv_label_set_text(label1, "  -");
        lv_label_set_text(label2, "-");

        lv_watch_set_free_num(content, 1);
    } else if(type == 2) { /*set time*/
        char hour_opt[16];
        char min_opt[16];
        char sec_opt[16];
        memset(hour_opt, 0, 16);
        memset(min_opt, 0, 16);
        memset(sec_opt, 0, 16);

        alarm_get_optstr_from_num(date_time->tm_hour, 0, hour_opt, 2, 0);
        alarm_get_optstr_from_num(date_time->tm_min, 0, min_opt, 3, 0);
        alarm_get_optstr_from_num(date_time->tm_sec, 0, sec_opt, 3, 0);

        lv_roller_set_options(roller1, hour_opt, LV_ROLLER_MODE_NORMAL);
        lv_obj_set_event_cb(roller1,  alarm_time_roller_event_cb);

        lv_roller_set_options(roller2, min_opt, LV_ROLLER_MODE_NORMAL);
        lv_obj_set_event_cb(roller2, alarm_time_roller_event_cb);

        lv_roller_set_options(roller3, sec_opt, LV_ROLLER_MODE_NORMAL);
        lv_obj_set_event_cb(roller3, alarm_time_roller_event_cb);

        lv_label_set_text(label1, ":");
        lv_label_set_text(label2, ":");

        lv_watch_set_free_num(content, 2);
    }

    lv_roller_set_auto_fit(roller1, true);
    lv_roller_set_selected(roller1, 2, LV_ANIM_OFF);
    lv_watch_roller_set_sel_style(roller1, ht_ext->sel_str[0]);

    lv_roller_set_auto_fit(roller2, true);
    lv_roller_set_selected(roller2, 2, LV_ANIM_OFF);
    lv_watch_roller_set_sel_style(roller2, ht_ext->sel_str[1]);

    lv_roller_set_auto_fit(roller3, true);
    lv_roller_set_selected(roller3, 2, LV_ANIM_OFF);
    lv_watch_roller_set_sel_style(roller3, ht_ext->sel_str[2]);

    return content;
}

static void alarm_setting_create(lv_obj_t * par, uint8_t type, lv_event_cb_t ok_event, lv_event_cb_t can_event)
{
    hal_rtc_t time;
    memset(&time, 0, sizeof(hal_rtc_t));
    Hal_Rtc_Gettime(&time);
    alarm_date_time_roller_create(par, type, &time);

    lv_obj_t * content = lv_cont_create(par, NULL);
    lv_cont_set_fit2(content, LV_FIT_NONE, LV_FIT_TIGHT);
    lv_obj_set_width(content, LV_HOR_RES);
    lv_cont_set_layout(content, LV_LAYOUT_ROW_MID);
    LV_ASSERT_MEM(content);
    if(content == NULL) return;
    lv_obj_set_click(content, true);
    lv_obj_align(content, par, LV_ALIGN_IN_BOTTOM_MID, 0, -LV_VER_RES / 8);
    lv_obj_add_style(content, LV_CONT_PART_MAIN, &lv_style_transp);
    lv_obj_set_style_local_pad_left(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_pad_right(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 20);
    lv_obj_set_style_local_pad_inner(content, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 70);

    lv_obj_t * can_btn = lv_imgbtn_create(content, NULL);
    lv_imgbtn_set_src(can_btn, LV_BTN_STATE_RELEASED, ICON_CANCEL);
    lv_imgbtn_set_src(can_btn, LV_BTN_STATE_PRESSED, ICON_CANCEL);
    lv_obj_set_event_cb(can_btn, can_event);

    lv_obj_t * ok_btn = lv_imgbtn_create(content, NULL);
    lv_imgbtn_set_src(ok_btn, LV_BTN_STATE_RELEASED, ICON_OK);
    lv_imgbtn_set_src(ok_btn, LV_BTN_STATE_PRESSED, ICON_OK);
    lv_obj_set_event_cb(ok_btn, ok_event);
}

static void alarm_setting_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * par = lv_obj_get_parent(btn);
        uint8_t num = lv_obj_get_user_data(btn).user_num;

        if(num == 0) {
            lv_obj_t * cont = lv_cont_create(par, NULL);
            lv_obj_set_size(cont, LV_HOR_RES, LV_VER_RES);
            lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_watch_black_tight);
            Hal_Rtc_Enable_Alarm(RTC_ALARM_1, false);
            alarm_setting_create(cont, 1, alarm_setting_datetime_ok_btn_event_cb, alarm_setting_datetime_cancel_btn_event_cb);//date
        } else if(num == 1) {
            Hal_Rtc_Enable_Alarm(RTC_ALARM_1, false);
            Hal_NFFS_File_Play_End();
            lv_obj_del(lv_obj_get_child(par, NULL));
            lv_label_set_text_id(lv_obj_get_child(btn, NULL), WATCH_TEXT_ID_EMODE_HW_ALARM_SETTINE);
            lv_watch_set_free_num(btn, 0);
        }
    }
}

static void alarm_setting_datetime_cancel_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    if(LV_EVENT_CLICKED == e) {
        lv_obj_t * par_obj = lv_obj_get_parent(lv_obj_get_parent(btn));
        lv_obj_del(par_obj);
    }
}

static void alarm_setting_datetime_ok_btn_event_cb(lv_obj_t * btn, lv_event_t e)
{
    char sel_str[12];
    char sel_str1[6];
    char sel_str2[4];
    char sel_str3[4];
    hal_rtc_t date_time;
    if(LV_EVENT_CLICKED == e) {
        lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
        lv_obj_t * par = lv_obj_get_parent(lv_obj_get_parent(btn));
        lv_obj_t * roller_cont = lv_obj_get_child(par, lv_obj_get_parent(btn));
        lv_obj_t * roller1 = ht_ext->roller[0];
        lv_obj_t * roller2 = ht_ext->roller[1];
        lv_obj_t * roller3 = ht_ext->roller[2];

        memset(sel_str, 0, 12);
        memset(sel_str1, 0, 6);
        memset(sel_str2, 0, 4);
        memset(sel_str3, 0, 4);
        lv_roller_get_selected_str(roller1, sel_str1, 6);
        lv_roller_get_selected_str(roller2, sel_str2, 4);
        lv_roller_get_selected_str(roller3, sel_str3, 4);
        if(lv_obj_get_user_data(roller_cont).user_num == 1) {
            snprintf(sel_str, 12, "%s-%s-%s", sel_str1, sel_str2, sel_str3);
            lv_label_set_text(ht_ext->date_label, sel_str);
            lv_obj_align(ht_ext->date_label, NULL, LV_ALIGN_CENTER, 0, 0);
        } else if(lv_obj_get_user_data(roller_cont).user_num == 2) {
            snprintf(sel_str, 12, "%s:%s:%s", sel_str1, sel_str2, sel_str3);
            lv_label_set_text(ht_ext->time_label, sel_str);
            lv_obj_align(ht_ext->time_label, ht_ext->date_label, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
        }

        if(lv_obj_get_user_data(roller_cont).user_num == 1) {
            alarm_setting_create(par, 2, alarm_setting_datetime_ok_btn_event_cb, alarm_setting_datetime_cancel_btn_event_cb);//time
            lv_obj_del(lv_obj_get_parent(btn));
            lv_obj_del(roller_cont);
            lv_obj_del(lv_obj_get_child_back(par, NULL));

        } else if(lv_obj_get_user_data(roller_cont).user_num == 2) {
            memset(&date_time, 0, sizeof(hal_rtc_t));
            memset(sel_str, 0, 12);
            strncpy(sel_str, lv_label_get_text(ht_ext->date_label), 12);
            alarm_get_num_from_string(sel_str, "-", &date_time);

            memset(sel_str, 0, 12);
            strncpy(sel_str, lv_label_get_text(ht_ext->time_label), 12);
            alarm_get_num_from_string(sel_str, ":", &date_time);
            lv_obj_del(par);
            Hal_Rtc_Set_Alarm(RTC_ALARM_1, &date_time, alarm_active_callback);
            Hal_Rtc_Enable_Alarm(RTC_ALARM_1, true);
        }
    }
}

static void alarm_active_callback(void)
{
    lv_engineer_hardware_testing_obj_ext_t * ext = hardware_testing_get_ext();

    lv_obj_t * par = lv_obj_get_parent(ext->date_label);
    lv_obj_t * cont = lv_cont_create(par, NULL);
    lv_obj_set_size(cont, LV_HOR_RES - 60, LV_VER_RES - 90);
    lv_obj_set_pos(cont, 30, 80);
    lv_obj_add_style(cont, LV_CONT_PART_MAIN, &lv_watch_cont_opa1);
    lv_obj_t * img = lv_img_create(cont, NULL);
    lv_img_set_src(img, ICON_SETTING_RING_MUSIC);
    lv_obj_align(img, NULL, LV_ALIGN_IN_TOP_MID, 0, 30);
    lv_obj_t * label = lv_label_create(cont, NULL);
    lv_label_set_text(label, lv_label_get_text(ext->time_label));
    lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font30_yellow);
    lv_obj_align(label, img, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

    lv_label_set_text(ext->date_label, "");
    lv_label_set_text(ext->time_label, "");
    Hal_File_Play_Onetime(AUDIO_INCOMING_CALL, query_current_volume(), NULL, NULL, 0);

    lv_obj_t * btn = lv_obj_get_child_back(par, lv_obj_get_child_back(par, NULL));
    lv_label_set_text_id((lv_obj_get_child(btn, NULL)), WATCH_TEXT_ID_EMODE_HW_ALARM_STOP);
    lv_watch_set_free_num(btn, 1);
}

static void alarm_get_num_from_string(char * str, char * delimiters, hal_rtc_t * date_time)
{
    char * temp;
    uint8_t date = 0;
    if(strcmp(delimiters, "-") == 0) {
        date = 1;
    }

    temp = strtok(str, delimiters);
    if(temp) {
        if(date)
            date_time->tm_year = atoi(temp);
        else
            date_time->tm_hour = atoi(temp);
        temp = strtok(NULL, delimiters);
        if(temp) {
            if(date)
                date_time->tm_mon = atoi(temp);
            else
                date_time->tm_min = atoi(temp);
            temp = strtok(NULL, delimiters);
            if(temp) {
                if(date)
                    date_time->tm_mday = atoi(temp);
                else
                    date_time->tm_sec = atoi(temp);
            }
        }
    }
}

static void hardware_testing_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
}

static void hardware_testing_item_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    if(NULL != ht_ext->timer) {
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
    }
}

static void emht_camera_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    if(NULL != ht_ext->timer) {
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
    }
    camera_destory();
}

static void emht_speaker_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    if(NULL != ht_ext->timer) {
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
    }
    Hal_NFFS_File_Play_End();
}

static void emht_micphone_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    if(NULL != ht_ext->timer) {
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
    }
    Hal_Tone_Play_End();
    if(NULL != ht_ext->record_task) {
        lv_task_del(ht_ext->record_task);
        ht_ext->record_task = NULL;
    }
    uint32_t duration_ms;
    Hal_Record_Buffer_Stop_Req(&ht_ext->buffer_size, &duration_ms);
    if(NULL != ht_ext->buffer) {
        LV_ASSERT_MEM(ht_ext->buffer);
        ht_ext->buffer = NULL;
    }
}

static void emht_backlight_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    if(NULL != ht_ext->timer) {
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
    }
    setting_set_backlight_intensity(setting_get_backlight_intensity(), true);
}

static void emht_vibration_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    if(NULL != ht_ext->timer) {
        Hal_Timer_Stop(ht_ext->timer);
        ht_ext->timer = NULL;
    }
    Hal_Vibrator_Play_End();
}

static void emht_tp_pointer_prepare_destroy(lv_obj_t * par)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * tp_pointer_ext = hardware_testing_get_ext();
    tp_pointer_ext->module = HW_MAX;

    lv_obj_t * childobj = lv_obj_get_child(tp_pointer_ext->tp_content, NULL);

    while(childobj) {
        if(NULL != lv_obj_get_user_data_ptr(childobj))
            LV_ASSERT_MEM(lv_obj_get_user_data_ptr(childobj));
        lv_obj_del(childobj);
        childobj = lv_obj_get_child(tp_pointer_ext->tp_content, NULL);
    }
}

static void emht_alarm_prepare_destory(lv_obj_t * activity_obj)
{
    lv_watch_png_cache_all_free();
    lv_engineer_hardware_testing_obj_ext_t * ht_ext = hardware_testing_get_ext();
    ht_ext->module = HW_MAX;
    Hal_Rtc_Enable_Alarm(RTC_ALARM_1, false);
    Hal_NFFS_File_Play_End();
}

#endif /*USE_LV_WATCH_ENGINEER_MODE*/
